package com.cdeledu.AbstractQueuedSynchronizer;

import java.util.concurrent.locks.AbstractQueuedSynchronizer;

public class ReentrantLock {

	private static final class Sync extends AbstractQueuedSynchronizer {

		protected boolean tryAcquire(int acquires) {
			final Thread current = Thread.currentThread();
	        int c = getState();
	        if (c == 0) {
	            if (compareAndSetState(0, acquires)) {
	                setExclusiveOwnerThread(current);
	                return true;
	            }
	        }
	        else if (current == getExclusiveOwnerThread()) {
	            int nextc = c + acquires;
	            if (nextc < 0) // overflow
	                throw new Error("Maximum lock count exceeded");
	            setState(nextc);
	            return true;
	        }
	        return false;
		}

		// 独占模式的unlock方法比共享模式简单许多，tryRelease判断条件就是如果自己没加锁缺想解锁，这不搞笑吗？直接异常抛出。接下来判断自己占用了几层锁，如果解到最后一层后才宣布锁被我释放了。
		//之后会通知后继节点。对比共享模式的通知所有等待的节点，独占模式只对当前节点的后继节点有通知的义务。
		protected final boolean tryRelease(int releases) {
	        int c = getState() - releases;
	        if (Thread.currentThread() != getExclusiveOwnerThread())
	            throw new IllegalMonitorStateException();
	        boolean free = false;
	        if (c == 0) {
	            free = true;
	            setExclusiveOwnerThread(null);
	        }
	        setState(c);
	        return free;
	    }

	}

	private final Sync sync;

	public ReentrantLock() {
		this.sync = new Sync();
    }

	public void lock() {
        sync.acquire(1);
    }

	public void unlock() {
	    sync.release(1);
	}

	public static void main(String[] args) {
		int N = 10;
		ReentrantLock lock = new ReentrantLock();
		CountDownLatch startSignal = new CountDownLatch(1);
		for (int i = 0; i < N; ++i) // create and start threads
            new Thread(new Worker(lock, startSignal), "t" + i).start();
		startSignal.countDown();
	}

	static class Worker implements Runnable {
        private final ReentrantLock lock;
        private final CountDownLatch startSignal;
        Worker(ReentrantLock lock, CountDownLatch startSignal) {
            this.lock = lock;
            this.startSignal = startSignal;
        }
        public void run() {
        	try {
				startSignal.await();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
        	lock.lock();
            doWork();
            lock.unlock();
        }

        void doWork() {
        	try {
				Thread.sleep(10);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
        	System.out.println("working...." + Thread.currentThread().getName());
        }

    }

}
